import { _decorator, Component, Node, find, UITransform, instantiate, Input, input, EventKeyboard, KeyCode, Color, color, Vec2, Vec3, tween, AudioSource, sys, MotionStreak, SpriteFrame, Texture2D, director, PhysicsSystem2D } from 'cc';
import { MapCtrl } from '../Ctrl/MapCtrl';
import { PlayerCtrl } from '../Ctrl/PlayerCtrl';
import { UICtrl } from '../Ctrl/UICtrl';
import { Unit, UnitEvent } from '../Entity/Unit';
import { Global, GuideTipData, PlayerData, RelicType, TechnologyType, UnitMsg, UnitType } from '../Util/Global';
import GameEventMgr, { GameEvent } from './GameEventMgr';
import { UnitPlanet } from '../Entity/UnitPlanet';
import { EconomicCom } from '../Entity/Component/EconomicCom';
import AssetsMgr from './AssetsMgr';
import { Tools } from '../Util/Tools';
import { FactoryCom } from '../Entity/Component/FactoryCom';
import { UnitSun } from '../Entity/UnitSun';
import SoundCtrl from '../Ctrl/SoundCtrl';
import { GameOverDialog } from '../UI/Dialog/GameOverDialog';
import { LevelUpCom } from '../Entity/Component/LevelUpCom';
import { LocalStorageCtrl, StorageKey } from '../Ctrl/LocalStorageCtrl';
import { UnitPlanetBase } from '../Entity/UnitPlanetBase';
import PoolManager from '../Ctrl/PoolManager';
import { GameOverTipDialog } from '../UI/Dialog/GameOverTipDialog';
import { StartGameViewUI } from '../UI/Component/StartGameViewUI';
const { ccclass, property } = _decorator;

@ccclass('GameManager')
export class GameManager extends Component {

    mapCtrl: MapCtrl = null;
    playerCtrl: PlayerCtrl = null;
    uiCtrl: UICtrl = null;
    gameUI: Node = null;//游戏场景uiRoot

    currentUnitLive: Set<Unit> = new Set();
    currentUnitLiveMap: Map<UnitType, Set<Unit>> = new Map();
    get_all_unit_count(type?: UnitType) {
        if (!type) {
            return this.currentUnitLive.size;
        }
        else {
            return this.currentUnitLiveMap.get(type)?.size || 0;
        }
    }

    historyTotalCount: number = 0;

    playerUnit: UnitPlanet = null;

    playerData: PlayerData = null;

    get gameover(): boolean {
        return !this.playerUnit || this.playerUnit.death;
    }

    private fristGame = true;
    protected onLoad() {
        Global.gameManager = this;
        GameEventMgr.Register(this, GameEvent.UnitInitComplete, this.UnitInitEventHandler.bind(this));
        GameEventMgr.Register(this, GameEvent.UnitDestroy, this.UnitDestroyEventHandler.bind(this));
        GameEventMgr.Register(this, GameEvent.UnitEnterScreenField, this.UnitEnterScreenField.bind(this));
        GameEventMgr.Register(this, GameEvent.OnClickBackHome, this.OnBackHome.bind(this));

        // 在节点启用时添加键盘事件监听器
        input.on(Input.EventType.KEY_DOWN, this.onKeyDown, this);

        Global.GameNode = find("GameCanvas");
        Global.GameNodeTran = Global.GameNode.getComponent(UITransform);

        this.mapCtrl = Global.GameNode.getChildByName("MapCtrl").getComponent(MapCtrl);
        this.playerCtrl = this.node.getComponent(PlayerCtrl);
        this.uiCtrl = this.node.getComponent(UICtrl);

        this.gameUI = find("UICanvas/GameUI");

        this.playerData = new PlayerData();

        // this.playerData.level = 2;
        // this.playerData.difficulty = 2;
        // this.playerData.technologyPoint = 1000;

        // console.log('音效呢')
    }

    protected start(): void {
        SoundCtrl.playMusic('CosmicReverie');

        this.schedule(() => {
            GameEventMgr.Dispatch(GameEvent.OnSecondTick);

            if (this.rewardAdTime > 0) {
                this.rewardAdTime -= 1;
                GameEventMgr.Dispatch(GameEvent.OnResetRewardAdTime, this.rewardAdTime);
            }
            else {
                if (this.rewardAdTime != -1) {
                    GameEventMgr.Dispatch(GameEvent.OnResetRewardAdTime, 0);
                }
                this.rewardAdTime = -1;
            }
        }, 1);
    }

    protected UnitInitEventHandler(unit: Unit) {
        if (unit) {
            this.currentUnitLive.add(unit);
            let pool = this.currentUnitLiveMap.get(unit.unitType) || new Set();
            pool.add(unit);
            this.currentUnitLiveMap.set(unit.unitType, pool);
            if (unit.unitType >= UnitType.UnitAssault && unit.unitType <= UnitType.UnitSpacecra) {
                let _pool = this.currentUnitLiveMap.get(UnitType.UnitSpacecra) || new Set();
                _pool.add(unit);
                this.currentUnitLiveMap.set(UnitType.UnitSpacecra, _pool);
            }

            if (unit.unitType > UnitType.UnitSpacecra && unit.unitType < UnitType.UnitCommonStar) {
                let _pool = this.currentUnitLiveMap.get(UnitType.UnitCommonStar) || new Set();
                _pool.add(unit);
                this.currentUnitLiveMap.set(UnitType.UnitCommonStar, _pool);
            }

            UICtrl.Instance.UpdateMapInfo();
        }
    }

    private _needShowAgainDialog: boolean = true;
    protected UnitDestroyEventHandler(unit: Unit, reason: string) {

        this.currentUnitLive.delete(unit);
        let pool = this.currentUnitLiveMap.get(unit.unitType) || new Set();
        pool.delete(unit);
        this.currentUnitLiveMap.set(unit.unitType, pool);
        if (unit.unitType >= UnitType.UnitAssault && unit.unitType <= UnitType.UnitSpacecra) {
            let _pool = this.currentUnitLiveMap.get(UnitType.UnitSpacecra) || new Set();
            _pool.delete(unit);
            this.currentUnitLiveMap.set(UnitType.UnitSpacecra, _pool);
        }

        if (unit.unitType > UnitType.UnitSpacecra && unit.unitType < UnitType.UnitCommonStar) {
            let _pool = this.currentUnitLiveMap.get(UnitType.UnitCommonStar) || new Set();
            _pool.delete(unit);
            this.currentUnitLiveMap.set(UnitType.UnitCommonStar, _pool);
        }

        if (unit.unitType >= UnitType.UnitAssault) {

            if (Tools.IsPositionInScreen(unit.unitWorldPos)) {
                SoundCtrl.playEffect("boom", 0.5);
            }
        }

        if (unit == this.playerUnit && this._needShowAgainDialog) {
            GameEventMgr.Dispatch(GameEvent.PlayerDestroy, unit);
            this.onPlayerDeathHandler();
            PoolManager.clearAllPools();
        }

        UICtrl.Instance.UpdateMapInfo();

        //打印死亡信息
        // GameEventMgr.Dispatch(GameEvent.LogGameMessage, reason);
    }

    //玩家死亡处理 游戏结束
    private onPlayerDeathHandler() {

        let dialog = UICtrl.showDialog(GameOverDialog).setData({ overType: 2 });
        dialog.afterDestroy = () => {
            if (this.playerUnit == null && this._needShowAgainDialog) {
                UICtrl.showDialog(GameOverTipDialog);
            }
        };

        this.mapCtrl.player = null;
        this.mapCtrl.mapSpawner.ClearWorkShop();

        this.playerUnit?.getComponent(MotionStreak)?.destroy();

        this.playerUnit = null;
        this.playerCtrl.playerUnit = null;
    }

    time: number = 0;
    rewardAdTime: number = -1;
    protected update(dt: number): void {

        SoundCtrl.effectPlayTick(dt);

        if (!this.gameover && !Global.gameManager.pause) {
            this.time += dt;
            this.uiCtrl.gameTimeLabel.string = Tools.secondsToTimeString(this.time);
            let cur_df = Math.floor(this.time / 180) + 1;
            if (cur_df > this.playerData.difficulty && Global.config['levelCfg'][cur_df]) {//三分钟升一级难度
                this.playerData.difficulty = cur_df;
                this.mapCtrl.mapSpawner.ChangeSpawnWeight(this.playerData.difficulty);
                GameEventMgr.Dispatch(GameEvent.PlayerDataChange);
            }
        }
    }

    private _pause = false;
    public set pause(val: boolean) {
        // val ? director.pause() : director.resume();
        this._pause = val;

        PhysicsSystem2D.instance.enable = !val;
    }
    public get pause() {
        return this._pause;
    }

    onKeyDown(event: EventKeyboard) {
        if (event.keyCode === KeyCode.KEY_E && sys.isBrowser) {

            Global.GravityCricleRenderer = !Global.GravityCricleRenderer;
            Global.LinearVelocityRenderer = !Global.LinearVelocityRenderer;
            Global.MapBlockRenderer = !Global.MapBlockRenderer;

            this.mapCtrl && this.mapCtrl.drawMapBlock(Global.MapBlockRenderer);
        }
        else if (event.keyCode === KeyCode.KEY_B && sys.isBrowser) {

            Global.TrackerDebug = !Global.TrackerDebug;
            GameEventMgr.Dispatch(GameEvent.OnTrackerDebug);
        }
        else if (event.keyCode === KeyCode.SPACE) {
            this.pause = !this.pause;
        }
    }

    public OnBackHome() {
        this._needShowAgainDialog = false;
        this.playerCtrl.allowCtrl = false;
        this.ResetGame();
        let newPlayer = PoolManager.getNode(AssetsMgr.getUnitPrefab(UnitType.UnitPlanet)).getComponent(UnitPlanet);
        newPlayer.node.parent = Global.GameNode;
        newPlayer.node.setPosition(420, 0, 0);

        find('UICanvas/StartGameViewUI').getComponent(StartGameViewUI).startPlayer = newPlayer;
        this.playerCtrl.playerUnit = newPlayer;//提前绑定这个对象，让摄像机跟随移动
        this.mapCtrl.player = newPlayer;
        UICtrl.clearDialog();
    }

    public ResetGame() {
        GameEventMgr.Dispatch(GameEvent.LogGameMessage, "重置游戏");
        PoolManager.clearAllPools();
        this._needShowAgainDialog = false;
        this.rewardAdTime = -1;
        this.currentUnitLive.forEach(v => {
            v.DestroySelf('重置');
        })
        this.node.setPosition(0, 0, 0);

        // let sun = instantiate(AssetsMgr.unitPrefabMap.get(UnitType.UnitSun)[0]).getComponent(UnitSun);
        let sun = PoolManager.getNode(AssetsMgr.getUnitPrefab(UnitType.UnitSun)).getComponent(UnitSun);
        sun.node.setPosition(0, 0, 0);
        sun.node.parent = Global.GameNode;

        this.fristGame = true;
        this.time = 0;
        this.mapCtrl.mapSpawner.enableSpawn = false;

        this.playerData.level = 1;
        this.playerData.difficulty = 1;
        this.playerData.technologyProduct.clear();
        this.playerData.technologyPoint = 0;
        this.playerData.relics.clear();
        this.mapCtrl.mapSpawner.ChangeSpawnWeight(this.playerData.difficulty);

        GameEventMgr.Dispatch(GameEvent.GameReset);
    }

    public GameStart(pos?: Vec3) {
        //实例化 玩家
        if (!this.gameover) {
            this.playerUnit.DestroySelf();
            this.playerUnit = null;
        }

        // let newPlayer = instantiate(AssetsMgr.unitPrefabMap.get(UnitType.UnitPlanet)[0]).getComponent(UnitPlanet);
        let newPlayer = PoolManager.getNode(AssetsMgr.getUnitPrefab(UnitType.UnitPlanet)).getComponent(UnitPlanet);
        newPlayer.node.parent = Global.GameNode;
        let spawnPos = pos || this.node.getWorldPosition()
        newPlayer.node.setWorldPosition(spawnPos);

        this.GameStartByUnit(newPlayer);
    }

    private gameViewScaleAnim() {
        if (Global.CameraOrthoScale == 2) {
            this.FirstPlayerTutorial();
            return;
        }
        Global.CameraOrthoHeight = Global.designScreenSize.height / 2;//设置视角为最小
        this.playerCtrl.allowCtrl = false;
        this.playerCtrl.gameUIView = true;
        let scale = Vec3.ONE.clone();
        tween(this.node).by(1, {}, {
            onUpdate: (target, ratio) => {
                Global.CameraOrthoHeight = Global.designScreenSize.height * (1 + ratio) / 2;
                scale.x = Global.CameraOrthoHeight / Global.designScreenSize.height * 2;
                scale.y = Global.CameraOrthoHeight / Global.designScreenSize.height * 2;
                this.playerCtrl.node.scale = scale;
            }
        }).call(() => {
            this.playerCtrl.allowCtrl = true;

            // if (!LocalStorageCtrl.getBooleanValue(StorageKey.FPTutorialFinish)) {
            this.FirstPlayerTutorial();
            // }
        }).start();
    }

    public GameStartByUnit(playerUnit: UnitPlanet) {
        if (playerUnit == null || !playerUnit.node) {
            return;
        }

        this._needShowAgainDialog = true;
        this.playerUnit = playerUnit;
        this.playerUnit.node.parent = Global.GameNode;
        this.playerUnit.messageLabel.node.active = true;

        this.playerUnit.on(this, UnitEvent.EconomicComBroken, () => {
            this.onPlayerDeathHandler();
        });

        this.gameUI.active = true;
        this.playerCtrl.allowCtrl = true;

        this.playerUnit.playerCtrl = true;
        this.playerUnit.SetBodyColor(new Color("#0DC281"));
        this.playerCtrl.playerUnit = this.playerUnit;

        this.mapCtrl.player = this.playerUnit;
        // this.mapCtrl.mapUnits.push(this.playerUnit);

        let trail = this.playerUnit.getComponent(MotionStreak) || this.playerUnit.addComponent(MotionStreak);
        trail.fastMode = true;
        trail.fadeTime = 0.5;
        AssetsMgr.getRes('texture/trail/spriteFrame', SpriteFrame, (sp) => {
            trail.texture = sp.texture as Texture2D;
        })

        //添加经济模块
        let economic = this.playerUnit.getComponent(EconomicCom) || this.playerUnit.addComponent(EconomicCom);
        economic.mine_res = this.playerData.level * 200;

        //添加工厂模块
        let factory = this.playerUnit.getComponent(FactoryCom) || this.playerUnit.addComponent(FactoryCom);
        factory.autoWorking = false;

        //添加升级模块
        let levelCom = this.playerUnit.getComponent(LevelUpCom) || this.playerUnit.addComponent(LevelUpCom);
        levelCom.level = this.playerData.level;

        this.uiCtrl.economicViewUI.target_economic = economic;
        this.uiCtrl.factoryViewUI.target_factory = factory;
        this.uiCtrl.skillViewUI.target_levelCom = levelCom;

        UICtrl.Instance.UpdateMapInfo();

        this.scheduleOnce(() => {
            if (!this.gameover) {
                GameEventMgr.Dispatch(GameEvent.GameStart);
            }

            UICtrl.clearDialog();
        })

        if (this.fristGame) {
            this.gameViewScaleAnim();
        }
        else {
            //重生且没完成引导
            if (!LocalStorageCtrl.getBooleanValue(StorageKey.FPTutorialFinish)) {
                this.FirstPlayerTutorial();
            }
            else {

                LocalStorageCtrl.setItem(StorageKey.FPTutorialFinish, true);
            }
        }

        // sys.localStorage.clear();
        this.fristGame = false;

        if (this._first_capture_asteroid) {
            this.playerUnit.on(this, UnitEvent.EnterSelfPlanetGravity, (planet: UnitPlanetBase) => {
                if (planet.unitType == UnitType.UnitAsteroid && planet.forceTrackTarget == this.playerUnit) {//第一次捕获小行星
                    this.playerUnit.off(this, UnitEvent.EnterSelfPlanetGravity);
                    this._first_capture_asteroid = false;

                    let pos = new Vec3(100, 100)
                    UICtrl.CreateGuideMessageOnGameScene({
                        message: '捕获一颗小行星！！！',
                        offset: pos,
                        target: planet.node,
                        GameLayer: true,
                        fontSize: 40,
                        GuideLineSize: 4,
                        lifeTime: 5,
                    }).NextGuideOnDestroy({
                        message: '制造一个采矿飞船可以采集资源！',
                        offset: pos,
                        target: planet.node,
                        GameLayer: true,
                        fontSize: 40,
                        GuideLineSize: 4,
                        lifeTime: 5,
                    })
                }
            })
        }
    }

    UnitEnterScreenField(unit: Unit) {
        this.UnitFirstOccurrenceMsgTip(unit);
    }

    private _first_capture_asteroid: boolean = true;
    private _first_spawned_spacecraft: boolean = true;
    FirstPlayerTutorial() {
        // if (!Global.UsingFixedJoystick) {
        //     LocalStorageCtrl.setItem(StorageKey.FPTutorialFinish, true);
        //     return;
        // }
        if (!this.playerUnit) {
            return
        }
        this._first_capture_asteroid = true;

        let sun: UnitSun = null;
        let sunTip = null;
        this.playerUnit.FilterOtherImpactPlanet_One((planet) => {
            if (planet.unitType == UnitType.UnitSun) {
                sun = planet as UnitSun;
                return true;
            }
            return false;
        })

        let start_engine = false;
        if (sun) {
            sun.onCheckRocheLimitShow();
            sunTip = UICtrl.CreateGuideMessageOnGameScene({
                message: '太阳',
                offset: new Vec3(200, 200),
                target: sun.node,
                GameLayer: true,
                fontSize: 40,
                GuideLineSize: 4,
                lifeCondition: () => {
                    if (sunTip && sun) {
                        let time = sun.helium_countdown.toFixed(2);
                        sunTip.messageLabel.string = sun.helium_countdown > 0 ?
                            `太阳氦闪(${time}后爆发)` : '太阳';
                    }
                    //未启动引擎或氦闪倒计时
                    return !start_engine || sun.helium_countdown > 0;
                }
            });
        }

        let guideData1: GuideTipData = {
            message: '拨动摇杆启动行星发动机！',
            offset: new Vec3(200, 100),
            fontSize: 20,
            target: this.playerCtrl.playCtrlUI.node,
            GameLayer: false,
            animInterval: 0.02,
            lifeCondition: () => {
                return !this.playerCtrl.playerMoveView.active;
            }
        };

        if (!Global.UsingFixedJoystick) {
            guideData1 = {
                message: '滑动屏幕启动行星发动机！',
                offset: new Vec3(200, 100),
                fontSize: 40,
                GuideLineSize: 4,
                target: this.playerUnit.node,
                GameLayer: true,
                animInterval: 0.02,
                lifeCondition: () => {
                    return !this.playerCtrl.playerMoveView.active;
                }
            };
        }

        let guideData2: GuideTipData = {
            message: '注意行星发动机推力方向！',
            fontSize: 20,
            offset: new Vec3(100, 0),
            target: this.playerCtrl.playerMoveView,
            GameLayer: false,
            animInterval: 0.02,
            lifeTime: 5
        };
        let guide1 = UICtrl.CreateGuideMessageOnGameScene(guideData1);
        guide1.node.on(Node.EventType.NODE_DESTROYED, () => {
            if (this.gameover) {
                return;
            }
            start_engine = true;
            sun && (sun.helium_countdown = 3);
            UICtrl.CreateGuideMessageOnGameScene(guideData2);

            let part2 = () => {
                // if (sunTip && sunTip.node) {
                //     sunTip.node.destroy();
                // }

                UICtrl.CreateGuideMessageOnGameScene({
                    message: '注意燃料消耗，尽快捕获小行星采集资源',
                    offset: new Vec3(-100, -100),
                    target: this.uiCtrl.economicViewUI.econ_mine.node,
                    GameLayer: false,
                    lifeTime: 5,
                });

                this.scheduleOnce(() => {
                    if (this.gameover) {
                        return;
                    }
                    let pos = new Vec3(-100, -50);
                    UICtrl.CreateGuideMessageOnGameScene({
                        message: '点击制造，可制造飞船单位',
                        offset: new Vec3(-100, -50),
                        target: find('CtrlButton/BuildBtn', this.uiCtrl.factoryViewUI.node),
                        GameLayer: false,
                        lifeTime: 5,
                    }).NextGuideOnDestroy({
                        message: '每生产一个单位都会占用一定的电力资源！',
                        offset: pos,
                        target: this.uiCtrl.economicViewUI.econIconUI.power_icon,
                        GameLayer: false,
                        lifeTime: 5,
                    }).NextGuideOnDestroy({
                        message: '这是你当前的电力负载上限！',
                        offset: pos,
                        target: this.uiCtrl.economicViewUI.econ_elec.node,
                        GameLayer: false,
                        lifeTime: 5,
                    }).NextGuideOnDestroy({
                        message: '当有电力输出时会不断消耗资源！',
                        offset: pos,
                        target: this.uiCtrl.economicViewUI.econIconUI.power_icon,
                        GameLayer: false,
                        lifeTime: 5,
                    });
                }, 4);

                LocalStorageCtrl.setItem(StorageKey.FPTutorialFinish, true);
            }

            /**如果不在恒星下就直接开始 */
            if (this.playerUnit.bigStarCount <= 0) {

                part2();
            }
            else {
                GameEventMgr.Dispatch(GameEvent.TipGameMessage, 'MOSS：点火成功！再见了太阳系！！！', 5);
                this.playerUnit.on(this, UnitEvent.EixtOtherPlanetGravity, (planet: UnitPlanetBase) => {
                    if (this.playerUnit.death) {
                        return;
                    }
                    if (planet.unitType == UnitType.UnitSun) {
                        this.playerUnit.off(this, UnitEvent.EixtOtherPlanetGravity);
                        GameEventMgr.Dispatch(GameEvent.TipGameMessage, 'MOSS：已逃离太阳引力范围！！！', 5);

                        part2();
                    }
                })
            }

        });


    }

    private _unitFirstShowMap: Set<UnitType> = new Set();
    /**飞船单位第一次出现在屏幕上时，则弹提示说明 */
    UnitFirstOccurrenceMsgTip(unit: Unit) {
        if (unit.unitType > UnitType.UnitSpacecra || unit.unitType <= UnitType.Bullet) {
            return;
        }
        if (this._unitFirstShowMap.has(unit.unitType)) {
            return;
        }
        else if (unit.parentUnit != null && unit.parentUnit == this.playerUnit) {
            let msg = UnitMsg.msgMap.get(unit.unitType);
            let desc = '新单位！！！';
            if (msg) {
                desc = msg.des;
            }
            UICtrl.CreateGuideMessageOnGameScene({
                message: desc,
                offset: new Vec3(100, 100),
                target: unit.node,
                GameLayer: true,
                fontSize: 40,
                GuideLineSize: 4,
                lifeTime: 5,
            });
            this._unitFirstShowMap.add(unit.unitType);

            if (this._first_spawned_spacecraft) {
                this._first_spawned_spacecraft = false;

            }
        }
    }
}


